﻿using System.Linq;
using Microsoft.Practices.ServiceLocation;
using Pap.Core.Utilities;
using Pap.Data;
using Utils.Data;

namespace Pap.Services.Sync.SqlProvider
{
    using System;
    using System.Configuration;
    using System.Data;
    using System.IO;

    using Pap.Core.Sync;

    public class DbSyncProvider : ISyncProvider
    {
        #region Fields

        private readonly string _applyChangesSpFormat;
        private readonly string _beginSessionSpName;
        private readonly string _connectionString;
        private readonly string _endSessionSpName;
        private readonly bool _filteringEnabled;
        private readonly Guid _remotePeer;
        private readonly string _selectChangesSpFormat;

        private byte[] _lastSyncVersion;

        #endregion Fields

        #region Constructors

        public DbSyncProvider(string selectChangesSpFormat,
            string applyChangesSpFormat,
            string beginSessionSpName,
            string endSessionSpName,
            string filteringEnabled,
            string connectionStringKey,
            string remotePeer)
        {
            _selectChangesSpFormat = selectChangesSpFormat;
            _applyChangesSpFormat = applyChangesSpFormat;
            _beginSessionSpName = beginSessionSpName;
            _endSessionSpName = endSessionSpName;
            _filteringEnabled = bool.Parse(filteringEnabled);
            _connectionString = ConfigurationManager.ConnectionStrings[connectionStringKey].ConnectionString;
            _remotePeer = new Guid(remotePeer);
        }

        #endregion Constructors

        #region Methods

        public void ApplyChanges(DataTable dtTable)
        {
            StringWriter writer = new StringWriter();
            RemoveTimezoneForDataSet(dtTable);
            dtTable.WriteXml(writer);

            var sp = new SqlStoredProcedureManager(_connectionString);
            sp.ProcedureName = string.Format(_applyChangesSpFormat, dtTable.TableName);
            sp.AddParameter("@RawValues", writer.ToString());
            sp.ExecuteNonQuery();
        }

        public static void RemoveTimezoneForDataSet(DataTable dt)
        {
            foreach (DataColumn dc in dt.Columns)
            {

                if (dc.DataType == typeof(DateTime))
                {
                    dc.DateTimeMode = DataSetDateTime.Unspecified;
                }
            }
         
        }

        public void BeginSession()
        {

            var currentCommitte =
                ServiceLocator.Current.GetInstance<IAdministrationRepository>().FindCommittees(
                    i => i.CommitteeID == RegistryInfo.CommitteeID).FirstOrDefault() ??
                ServiceLocator.Current.GetInstance<ICommittee>();

            var sp = new SqlStoredProcedureManager(_connectionString);
            sp.ProcedureName = _beginSessionSpName;
            sp.AddParameter("@PeerId", _remotePeer);
            sp.AddParameter("@CommitteeName", currentCommitte.CommitteeName);
            sp.AddParameter("@CenterID", currentCommitte.CenterID);
            sp.AddParameter("@IsMainCommittee", _filteringEnabled);
            this._lastSyncVersion = sp.ExecuteScaler() as byte[];
        }

        public void EndSession()
        {
            var sp = new SqlStoredProcedureManager(_connectionString);
            sp.ProcedureName = _endSessionSpName;
            sp.AddParameter("@PeerId", _remotePeer);
            sp.ExecuteNonQuery();
        }

        public DataTable SelectChanges(string tableName)
        {
            var sp = new SqlStoredProcedureManager(_connectionString);
            sp.ProcedureName = string.Format(_selectChangesSpFormat, tableName);
            sp.AddParameter("@LastRowVersion", _lastSyncVersion, DbType.Binary);
            sp.AddParameter("@FilterdColumn", _filteringEnabled ? (object)RegistryInfo.CommitteeID : DBNull.Value);
            var dt = new DataTable(tableName);
            sp.ExecuteDataTable(dt);
            return dt;
        }

        #endregion Methods
    }
}